#ifndef PW_PBL_IRQBUFFER_HPP
#define PW_PBL_IRQBUFFER_HPP

#include <concepts>
#include <atomic>
#include "RustMimic.hpp"
#include "Math.hpp"
#include "IntFor.hpp"

namespace pw_pbl
{
	template <typename BUF, std::unsigned_integral OPT_ERR = uint8_t>
	class RxIrqBuf;

	/// 针对中断式数据接收优化的缓冲区，抽象类型，主要用于提供未指定长度的收发器类型
	template <typename T, std::unsigned_integral OPT_ERR>
	class RxIrqBuf<T[], OPT_ERR>
	{
	public:
		class Recver;
	};

	/// 针对中断式数据接收优化的缓冲区
	template <typename T, std::size_t N, std::unsigned_integral OPT_ERR>
	class RxIrqBuf<T[N], OPT_ERR> : public RxIrqBuf<T[], OPT_ERR>
	{
		using index_type = UIntFor::Values<N - 1>;

		std::atomic<index_type> windex;
		std::atomic<index_type> rindex;
		std::atomic<OPT_ERR> err;
		MaybeUninit<T[N]> data;

		static_assert(std::atomic<index_type>::is_always_lock_free && std::atomic<OPT_ERR>::is_always_lock_free);

		static constexpr index_type step_index(index_type v)
		{
			if constexpr (Math::IsPow2(N))
			{
				constexpr index_type MASK = std::numeric_limits<index_type>::max() >> (Math::BitCntOf<index_type> - Math::Log2<N>);
				return v + 1 & MASK;
			}
			else
				return (v + 1) % N;
		}

		template <std::memory_order ODR, bool IRQ>
		static constexpr auto irq_odr = IRQ ? std::memory_order_relaxed : ODR;

		template <bool IRQ>
		void send_data(T v)
		{
			if (this->err.load(irq_odr<std::memory_order_acquire, IRQ>) == NoError)
			{
				index_type wi = this->windex.load(std::memory_order_relaxed);
				index_type nwi = step_index(wi);
				if (nwi != this->rindex.load(std::memory_order_relaxed))
				{
					this->data.get()[wi] = v;
					this->windex.store(nwi, irq_odr<std::memory_order_release, IRQ>);
				}
				else
					this->err.store(EOverflow, irq_odr<std::memory_order_release, IRQ>);
			}
		}

		Option<Result<T, NonZero<OPT_ERR>>> recv() noexcept
		{
			index_type ri = this->rindex.load(std::memory_order_relaxed);
			if (ri != this->windex.load(std::memory_order_relaxed))
			{
				auto out = Some(Result<T, NonZero<OPT_ERR>>::Ok(this->data.get()[ri]));
				this->rindex.store(step_index(ri), std::memory_order_release);
				return out;
			}
			else
			{
				OPT_ERR err = this->err.load(std::memory_order_seq_cst);
				if (err != NoError)
				{
					this->err.store(NoError, std::memory_order_release);
					return Some(Result<T, NonZero<OPT_ERR>>::Err(NonZero<OPT_ERR>::new_unchecked(err)));
				}
				else
					return None;
			}
		}

	public:
		class Sender;
		class Recver;

		constexpr RxIrqBuf() noexcept : windex{}, rindex{}, err{}, data{} {}
		constexpr Sender get_sender() { return {*this}; }
		constexpr Recver get_recver() { return {*this}; }

		static constexpr OPT_ERR NoError = 0;
		static constexpr OPT_ERR EOverflow = std::numeric_limits<OPT_ERR>::max();
		static constexpr OPT_ERR EInvalid = EOverflow - 1;
	};

	template <typename T, std::size_t N, std::unsigned_integral OPT_ERR>
	class RxIrqBuf<T[N], OPT_ERR>::Sender
	{
		RxIrqBuf &buffer;

		friend RxIrqBuf;

		constexpr Sender(RxIrqBuf &buf) noexcept : buffer(buf) {}

	public:
		/// 发送数据，注意：缓冲区已满发送超写溢出错误，或已有错误时则无操作
		void send_data(T v) { this->buffer.template send_data<false>(v); }

		/// 显式发送错误
		void send_err(NonZero<OPT_ERR> v) { this->buffer.err.compare_exchange_strong(NoError, v.raw, std::memory_order_acquire, std::memory_order_relaxed); }

		/// 针对IRQ或抢先式线程优化的发送数据方法
		void irq_send_data(T v) { this->buffer.template send_data<true>(v); }

		/// 针对IRQ或抢先式线程优化的发送错误方法
		void irq_send_err(NonZero<OPT_ERR> v)
		{
			if (this->buffer.err.load(std::memory_order_relaxed) == NoError)
				this->buffer.err.store(v.raw, std::memory_order_relaxed);
		}
	};

	template <typename T, std::size_t N, std::unsigned_integral OPT_ERR>
	class RxIrqBuf<T[N], OPT_ERR>::Recver
	{
		RxIrqBuf &buffer;

		friend RxIrqBuf;

		constexpr Recver(RxIrqBuf &buf) noexcept : buffer(buf) {}

	public:
		constexpr Recver(Recver &&) = default;
		Recver(const Recver &) = delete;
		constexpr Recver &operator=(Recver &&) = default;
		Recver &operator=(const Recver &) = delete;
		Option<Result<T, NonZero<OPT_ERR>>> try_recv() { return buffer.recv(); };
		Option<Result<T, NonZero<OPT_ERR>>> operator()() noexcept { return buffer.recv(); }
		Recver &recv() { return *this; }; // for ccAsyncRecv

		constexpr operator typename RxIrqBuf<T[], OPT_ERR>::Recver() &&
		{
			return {&buffer, [](void *pobj) { return reinterpret_cast<RxIrqBuf *>(pobj)->recv(); }};
		}
	};

	template <typename T, std::unsigned_integral OPT_ERR>
	class RxIrqBuf<T[], OPT_ERR>::Recver
	{
		using func_type = Option<Result<T, NonZero<OPT_ERR>>>(void *pobj);

		void *pobj;
		func_type *pfunc;

	public:
		constexpr Recver(void *_pobj, func_type *_pfunc) noexcept : pobj(_pobj), pfunc(_pfunc) {}

		constexpr Recver(Recver &&) = default;
		Recver(const Recver &) = delete;
		constexpr Recver &operator=(Recver &&) = default;
		Recver &operator=(const Recver &) = delete;
		Option<Result<T, NonZero<OPT_ERR>>> try_recv() { return pfunc(pobj); };
		Option<Result<T, NonZero<OPT_ERR>>> operator()() noexcept { return pfunc(pobj); }
		Recver &recv() { return *this; }; // for ccAsyncRecv
	};

} // namespace pw_pbl

#endif // PW_PBL_IRQBUFFER_HPP
